﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Autoupdate.Common
{
    public class DES
    {
        // 一次处理的明文字节数
        private static readonly int EncryptSize = 10000000;
        // 一次处理的密文字节数
        private static readonly int DecryptSize = 10000016;

        private byte[] mRgbKey;
        private byte[] mRgbIV;

        public DES()
        {
            mRgbKey = new byte[] { 0x64, 0x6C, 0x41, 0x4B, 0x63, 0x56, 0x49, 0x67 };
            mRgbIV = new byte[] { 0x18, 0x52, 0x36, 0x98, 0x90, 0xAE, 0xBE, 0xDF };
        }

        public DES(byte[] key, byte[] iv)
        {
            mRgbKey = key;
            mRgbIV = iv;
        }

        public string EncryptString(string encryptString)
        {
            try
            {
                if (string.IsNullOrEmpty(encryptString))
                    return encryptString;
                byte[] rgbKey = mRgbKey;
                byte[] rgbIV = mRgbIV;
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                byte[] outputByteArray = Encrypt(inputByteArray);
                return Convert.ToBase64String(outputByteArray);
            }
            catch
            {
                return encryptString;
            }
        }

        public string DecryptString(string decryptString)
        {
            try
            {
                if (string.IsNullOrEmpty(decryptString))
                    return decryptString;
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                byte[] outputByteArray = Decrypt(inputByteArray);
                return Encoding.UTF8.GetString(outputByteArray);
            }
            catch
            {
                return decryptString;
            }
        }

        public void EncryptFile(string path)
        {
            try
            {
                if (File.Exists(path + ".temp"))
                    File.Delete(path + ".temp");
                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    if (fs.Length > 0)
                    {
                        using (FileStream fsnew = new FileStream(path + ".temp", FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            if (File.Exists(path + ".temp")) File.SetAttributes(path + ".temp", FileAttributes.Hidden);
                            int blockCount = ((int)fs.Length - 1) / EncryptSize + 1;
                            for (int i = 0; i < blockCount; i++)
                            {
                                int size = EncryptSize;
                                if (i == blockCount - 1) size = (int)(fs.Length - i * EncryptSize);
                                byte[] bArr = new byte[size];
                                fs.Read(bArr, 0, size);
                                byte[] result = Encrypt(bArr);
                                fsnew.Write(result, 0, result.Length);
                                fsnew.Flush();
                                //refreshFileProgress(blockCount, i + 1); //更新进度
                            }
                            fsnew.Close();
                            fsnew.Dispose();
                        }
                        fs.Close();
                        fs.Dispose();
                        FileAttributes fileAttr = File.GetAttributes(path);
                        File.SetAttributes(path, FileAttributes.Archive);
                        File.Delete(path);
                        File.Move(path + ".temp", path);
                        File.SetAttributes(path, fileAttr);
                    }
                }
            }
            catch (Exception ex)
            {
                File.Delete(path + ".temp");
                throw ex;
            }
        }

        public void DecryptFile(string path)
        {
            try
            {
                if (File.Exists(path + ".temp"))
                    File.Delete(path + ".temp");
                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    if (fs.Length > 0)
                    {
                        using (FileStream fsnew = new FileStream(path + ".temp", FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            if (File.Exists(path + ".temp")) File.SetAttributes(path + ".temp", FileAttributes.Hidden);
                            int blockCount = ((int)fs.Length - 1) / DecryptSize + 1;
                            for (int i = 0; i < blockCount; i++)
                            {
                                int size = DecryptSize;
                                if (i == blockCount - 1) size = (int)(fs.Length - i * DecryptSize);
                                byte[] bArr = new byte[size];
                                fs.Read(bArr, 0, size);
                                byte[] result = Decrypt(bArr);
                                fsnew.Write(result, 0, result.Length);
                                fsnew.Flush();
                                //refreshFileProgress(blockCount, i + 1); //更新进度
                            }
                            fsnew.Close();
                            fsnew.Dispose();
                        }
                        fs.Close();
                        fs.Dispose();
                        FileAttributes fileAttr = File.GetAttributes(path);
                        File.SetAttributes(path, FileAttributes.Archive);
                        File.Delete(path);
                        File.Move(path + ".temp", path);
                        File.SetAttributes(path, fileAttr);
                    }
                }
            }
            catch (Exception ex)
            {
                File.Delete(path + ".temp");
                throw ex;
            }
        }

        private byte[] Encrypt(byte[] inputByteArray)
        {
            try
            {
                if (inputByteArray == null || inputByteArray.Length == 0)
                    return inputByteArray;
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(mRgbKey, mRgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return mStream.ToArray();
            }
            catch
            {
                return inputByteArray;
            }
        }

        private byte[] Decrypt(byte[] inputByteArray)
        {
            try
            {
                if (inputByteArray == null || inputByteArray.Length == 0)
                    return inputByteArray;
                DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(mRgbKey, mRgbIV), CryptoStreamMode.Write);
                cStream.Write(inputByteArray, 0, inputByteArray.Length);
                cStream.FlushFinalBlock();
                return mStream.ToArray();
            }
            catch
            {
                return inputByteArray;
            }
        }
    }
}
